package com.ymy.spring.cloud.sentinel.core.config;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.ArrayList;
import java.util.List;

import static com.alibaba.csp.sentinel.slots.block.RuleConstant.*;

/**
 * Sentinel 配置流控规则和{@link SentinelResource}使用的Bean。
 *
 * @author Ringo
 * @date 2021/10/5 18:18
 */
@Configuration
public class SentinelConfig {

    public static final String RESOURCE_NAME = "hello";
    public static final String USER_RESOURCE_NAME = "user";
    public static final String BOOK_RESOURCE_NAME = "book";
    public static final String DEGRADE_RESOURCE_NAME = "degrade";

    /**
     * Spring Boot 模式下使用 {@link SentinelResource} 需要配置 Bean
     */
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

    /**
     * 服务熔断降级规则：
     * 1. 触发熔断：20秒内触发4次异常就进行熔断, 断路时间为 10 s.
     * 2. 经过熔断时间窗口（timeWindow）后, 恢复接口的请求调用, 第一次调用接口, 又出现异常, 第二次直接就会熔断。
     */
    @Bean
    public void intDegradeRoles() {
        List<DegradeRule> rules = new ArrayList<>();
        DegradeRule rule = new DegradeRule();

        rule.setResource(DEGRADE_RESOURCE_NAME);

        // 异常数量进行服务降级
        rule.setGrade(DEGRADE_GRADE_EXCEPTION_COUNT)
                // 异常数量
                .setCount(4)
                // 熔断时常 单位:s。熔断降级独有的（和流控最大的区别）
                .setTimeWindow(10)
                // 熔断触发的最小请求数，请求数小于该值时即使异常比率超出阈值也不会熔断
                .setMinRequestAmount(2)
                .setStatIntervalMs(20000);

        rules.add(rule);
        DegradeRuleManager.loadRules(rules);
    }

    /**
     * 流控规则
     */
    @Bean
    public void initFlowRules() {
        // 流控规则
        List<FlowRule> rules = new ArrayList<>();

        // 流控规则
        FlowRule rule = new FlowRule();
        // 为哪个资源进行流控
        rule.setResource(RESOURCE_NAME);
        // 设置流控规则模式： QPS
        rule.setGrade(FLOW_GRADE_QPS);
        // Set limit QPS to 1.
        rule.setCount(1);
        rules.add(rule);

        // 流控规则1
        FlowRule rule1 = new FlowRule();
        rule1.setGrade(FLOW_GRADE_QPS).setCount(1).setResource(USER_RESOURCE_NAME);
        rules.add(rule1);

        // 流控规则2
        FlowRule rule2 = new FlowRule().setGrade(FLOW_GRADE_QPS).setCount(1);
        rule2.setResource(BOOK_RESOURCE_NAME);
        rules.add(rule2);

        FlowRuleManager.loadRules(rules);
    }
}
